package org.totoro.nio;

import org.junit.Test;

import java.nio.Buffer;
import java.nio.IntBuffer;

/**
 * nio 缓冲区
 * <p>
 * capacity：表示的是这个缓冲区包含元素的个数，容量不可改变也不可是负数
 * limit：表示的是缓冲区中第一个不可读或写的元素的索引，它不可是负数并且 <= capacity
 * position：表示的是缓冲区中下一个元素可读或可写的元素的索引，它不可是负数并且 <= limit
 *
 * @author daocr
 * @date 2020/7/2
 */
public class BufferTest {


    public final int five = 5;

    private void putData(IntBuffer allocate, int size) {
        for (int i = 0; i < size; i++) {
            allocate.put(i);
        }
    }

    /**
     * 读模式
     *
     * @see Buffer#flip()
     */
    @Test
    public void readMode() {

        IntBuffer allocate = allocate(10);

        putData(allocate, five);

        System.out.println("写入数据完成\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());

        allocate.flip();

        System.out.println("切换到读模式\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
    }

    /**
     * 部分重写
     *
     * @see IntBuffer#compact()
     */
    @Test
    public void compactMode() {

        IntBuffer allocate = allocate(10);
        putData(allocate, five);
        System.out.println("写入数据完成\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());

        System.out.println("------------------------------------------------------\n");
        System.out.println("切换到读模式");
        allocate.flip();
        System.out.println("切换到读\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        read(allocate, 2);
        System.out.println("读取完成\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());

        System.out.println("------------------------------------------------------\n");


        /**
         * 把未读取的数据，复制到前面，然后继续写入数据
         * 公式：下次写入下标=（总读取数据长度-已读书数据长度）
         */

        System.out.println("切换到写模式 compact");
        System.out.println("compact 前\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        allocate.compact();
        System.out.println("compact 后\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());

    }

    /**
     * 标记
     *
     * @see Buffer#mark()
     */
    @Test
    public void markAndRest() {

        IntBuffer allocate = allocate(10);
        putData(allocate, five);
        System.out.println("写入数据完成\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        System.out.println("------------------------------------------------------\n");

        System.out.println("mark 前 \t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        allocate.mark();
        System.out.println("mark 后 \t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        System.out.println("------------------------------------------------------\n");


        putData(allocate, 2);
        System.out.println("写入数据完成\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        System.out.println("------------------------------------------------------\n");


        System.out.println("reset 前 \t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        allocate.reset();
        System.out.println("reset 后 \t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        System.out.println("------------------------------------------------------\n");


        putData(allocate, 2);
        System.out.println("写入数据完成\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        System.out.println("------------------------------------------------------\n");

    }

    /**
     * 全部重写模式
     */
    @Test
    public void clearMode() {

        IntBuffer allocate = allocate(10);
        putData(allocate, five);
        System.out.println("写入数据完成\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        System.out.println("------------------------------------------------------\n");

        System.out.println("clear 前 \t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        allocate.clear();
        System.out.println("clear 后 \t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());


    }


    /**
     * 重读、或者重写
     *
     * @see Buffer#rewind()
     */
    @Test
    public void rewind() {

        IntBuffer allocate = allocate(10);

        System.out.println("开始写入\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        putData(allocate, five);
        System.out.println("结束写入\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        System.out.println("------------------------------------------------------\n");

        System.out.println("切换到重写模式");
        allocate.rewind();

        System.out.println("开始重写\t\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        putData(allocate, five);
        System.out.println("结束重写\t\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        System.out.println("------------------------------------------------------\n");


        System.out.println("切换到读模式");
        allocate.flip();
        System.out.println("开始读模式\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());

        read(allocate, five);
        System.out.println("结束读模式\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        System.out.println("------------------------------------------------------\n");

        allocate.rewind();

        System.out.println("开始重读模式\t\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());
        read(allocate, five);
        System.out.println("结束重读模式\t\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());


    }

    private void read(IntBuffer allocate, int size) {
        for (int i = 0; i < size; i++) {
            allocate.get();
        }
    }


    /**
     * 申请容量
     *
     * @param capacity
     * @return
     */
    private IntBuffer allocate(Integer capacity) {

        IntBuffer allocate = IntBuffer.allocate(capacity);

        System.out.println("申请容量\t\t\tposition：" + allocate.position() + "\tlimit： " + allocate.limit() + "\t 总容量 capacity：" + allocate.capacity());

        return allocate;
    }


}
